import 'dart:async';
import 'dart:io';

import 'package:blue_plugin/bean/characteristic_bean.dart';
import 'package:blue_plugin/bean/dev_find.dart';
import 'package:blue_plugin/bean/dev_info.dart';
import 'package:blue_plugin/bean/scan_result.dart';
import 'package:blue_plugin/utils/toast_util.dart';
import 'package:flutter/services.dart';

typedef BlueOffBack = Function(bool data);
typedef CheckBulePermission = Function(bool data, String errorMsg);
typedef BlueDevList = Function(String errormsg, List<ScanResults> devList);

//蓝牙的中央处理器,用于扫描设备以及底层通信
class BlueElves {
  static BlueElves instance = BlueElves._();
  late String CHANNEL_METHOD = "blue_plugin_method";
  late String EVENT_CHANNEL = "blue_plugin_event";

  late MethodChannel _channelBlue;
  late EventChannel _eventChannelPlugin;
  late StreamSubscription _eventStreamSubscription;

  late StreamController<ScanResults> _scanResultStreamController; ////扫描的集合
  late Function(bool isOk) _applyBluetoothPermissionCallback;
  late Function(bool isOk) _applyLocationPermissionCallback;
  late Function(bool isOk) _openLocationServiceCallback;
  late Function(bool isOk) _openBluetoothServiceCallback;
  late Function(bool isOk) _applyPermissionCallBack;
  late Function(bool isOk) _blueOffCallBack;
  late Function(bool isOk, String error) _connectedCallBack;
  late Function(List<CharacteristicBean> list) _characteristicBeanCallBack;
  late Function(Map<dynamic, dynamic> map) _characteristicBeanMapCallBack;
  late Function(bool isSuccess, dynamic data, dynamic strdata, String uuid)
      _valueMapCallBack; //测量值
  late Function(String devType, String json) _valueSDKJsonCallBack; //SDK 设备测量值
  late Function(String devTye,String state, String msg) _valueSDKStateCallBack; //SDK 设备测量状态
  List<ScanResults>? _scanResultList; //扫描的集合
  ScanResults? devInfo; //当前设备
  List<CharacteristicBean>? characteristicList; //特征值集合

  BlueElves._() {
    _channelBlue = MethodChannel(CHANNEL_METHOD);
    // 定义接收底层操作系统主动发来的消息通道
    _eventChannelPlugin = EventChannel(EVENT_CHANNEL);
    _eventStreamSubscription = _eventChannelPlugin
        .receiveBroadcastStream()
        .listen(_onToDart,
            onError: _onToDartError); //注册消息回调函数;//广播流来处理EventChannel发来的消息
  }

  void _onToDart(dynamic message) {
    //底层发送成功消息时会进入到这个函数来接收
    print("底层发送成功消息-onToDart--->${message}");
    switch (message['eventName']) {
      case "state":
        _blueOffCallBack(message['state']);
        break;
      case "allowApplyPermission":
        _applyPermissionCallBack(true);
        break;
      case "denyApplyPermission":
        _applyPermissionCallBack(false);
        break;
      case "allowBluetoothPermission":
        _applyBluetoothPermissionCallback(true);
        break;
      case "denyBluetoothPermission":
        _applyBluetoothPermissionCallback(false);
        break;
      case "allowLocationPermission":
        _applyLocationPermissionCallback(true);
        break;
      case "denyLocationPermission":
        _applyLocationPermissionCallback(false);
        break;
      case "allowLocationFunction":
        _openLocationServiceCallback(true);
        break;
      case "denyLocationFunction":
        _openLocationServiceCallback(false);
        break;
      case "allowOpenBluetooth":
        _openBluetoothServiceCallback(true);
        break;
      case "denyOpenBluetooth":
        _openBluetoothServiceCallback(false);
        break;
      case "scanResult":
        ScanResults item = ScanResults(
            message['id'],
            message['name'],
            message['localName'],
            message['macAddress'],
            message['rssi'],
            message['uuids'],
            message['manufacturerSpecificData'],
            message['scanRecord']);
        _scanResultStreamController.add(item); //将扫描到的新设备放到流中通知
        break;
      case "scanTimeout":
        _scanResultStreamController.close(); //扫描时间到了就关闭流,因为是单对单的流
        break;
      case "connected":
        _connectedCallBack(true, "1");
        break;
      case "connectTimeout":
        _connectedCallBack(false, "-1");
        break;
      case "initiativeDisConnected": //如果是手动断开连接
        _connectedCallBack(false, "-2");
        break;
      case "disConnected": //如果是被动断开连接
        _connectedCallBack(false, "-3");
        break;
      case "discoverService": //如果是发现了服务
        List characteristicsList = message['characteristic']; //底层发现的特征值列表信息
        List<CharacteristicBean> propertiesList = [];
        for (int i = 0; i < characteristicsList.length; i++) {
          //将特征值信息封装成对象
          Map characteristicsMap = characteristicsList[i];
          int properties =
              characteristicsMap["properties"]; //底层发现的特征值的properties
          String uuid = characteristicsMap["uuid"]; //底层发现的特征值的uuid
          String serviceUuid = characteristicsMap["serviceUuid"]; //底层发现的服务的uuid
          print("收到的特征值${properties}-uuid-${uuid}");
          propertiesList
              .add(new CharacteristicBean(uuid, serviceUuid, properties, ""));
        }
        _characteristicBeanCallBack(propertiesList);
        break;
      case "discoverServiceList": //如果是发现了服务集合
        Map<dynamic, dynamic> map = (message['serivcemap']); //底层发现的服务列表信息
        _characteristicBeanMapCallBack(map);
        break;
      case "deviceSignal": //如果是设备传来数据
        bool isSuccess = message['isSuccess'];
        dynamic data = message['data'];
        dynamic strdata = message['strdata'];
        String uuid = message['uuid'];
        _valueMapCallBack(isSuccess, data, strdata, uuid);
        break;
      case "mtuChange": //如果是设备mtu修改了
        break;
      case "rssiChange":
        break;
      case "sdkDevJson"://SDK设备
        String devType = message['devType'];//设备类型
        String json = message['json'];//数据
        if(_valueSDKJsonCallBack != null){
          _valueSDKJsonCallBack(devType,json);
        }
        break;
      case "sdkDevState"://设备状态
        String devType = message['devType'];//设备状态
        String state = message['state'];//状态
        String msg = message['msg'];//状态
        if(_valueSDKStateCallBack != null){
          _valueSDKStateCallBack(devType,state,msg);
        }
        break;
    }
  }

  void _onToDartError(dynamic error) {
    //底层发送错误消息时会进入到这个函数来接收
    ToastUtils.show("底层发过来的错误信息:${error}");
  }

  ///判断蓝牙是否开启
  Future<Object> getBlueOff(Function(bool isOk) callback) async {
    _blueOffCallBack = callback;
    var str = await _channelBlue.invokeMethod("state");
    return str;
  }

  ///解决掉所有权限
  checkPermission(CheckBulePermission callback) {
    Future.delayed(const Duration(milliseconds: 500), () {
      getBlueOff((data) {
        print("蓝牙是否连接:${data}");
        if (data) {
          //蓝牙开关打开了
          applyLocationPermission((isok) {
            //检查相关权限
            callback(isok, isok == true ? "" : "请允许相关权限才能正常使用该设备");
          });
        } else {
          //蓝牙开关未打开
          openBlue((isok) {
            if (!isok) {
              callback(isok, "请打开蓝牙开关");
            } else {
              applyLocationPermission((isok) {
                //检查相关权限
                callback(isok, isok == true ? "" : "请允许相关权限才能正常使用该设备");
              });
            }
          });
        }
      });
    });
  }

  ///调用底层去获取定位权限
  applyLocationPermission(Function(bool isOk) callback) async {
    _applyPermissionCallBack = callback;
    var str = await _channelBlue.invokeMethod("applyPermission");
    print("applyLocationPermission-返回值->${str}");
    _applyPermissionCallBack(str);
  }

  ///android 直接打开，
  Future<Object> openBlue(Function(bool isOk) callback) async {
    _openBluetoothServiceCallback = callback;
    var str = await _channelBlue.invokeMethod("openBlueOff");
    _openBluetoothServiceCallback(str);
    print("openBlue-返回值->${str}");
    return str;
  }

  ///开始扫描设备,返回扫描结果流
  Stream<ScanResults> scanDevList(int timeout,
      {bool isAllowDuplicates = false}) {
    _scanResultStreamController = StreamController<ScanResults>(
        onListen: () {
          _channelBlue.invokeMethod("startScan", {
            "isAllowDuplicates": isAllowDuplicates,
            "timeout": Platform.isAndroid ? timeout : timeout ~/ 1000
          });
        },
        onCancel: stopScanList);
    return _scanResultStreamController.stream;
  }

  startScan(int timeout, DevInfo devInfo, BlueDevList callback,
      {bool isAllowDuplicates = false}) {
    _scanResultList = [];
    scanDevList(timeout).listen((event) {
      _scanResultList!.insert(0, event);
    }).onDone(() {
      //时间到了
      if (_scanResultList!.isEmpty) {
        callback("未发现${devInfo.mark}", _scanResultList!);
      } else {
        List<ScanResults> _devList = [];
        for (var prop in _scanResultList!) {
          if (DEVFind.NAME == devInfo.devFind) {
            if (prop.name != null) {
              if (prop.name!.contains(devInfo.name!)) {
                _devList.insert(0, prop);
              }
            }
          }

          if (DEVFind.UUID == devInfo.devFind) {
            if (prop.uuids != null) {
              if (prop.uuids.contains(devInfo.uuid)) {
                _devList.insert(0, prop);
              }
            }
          }
        }

        if (_devList.isEmpty) {
          callback("未发现${devInfo.mark}", _devList);
        } else {
          callback("", _devList);
        }
      }
    });
  }

  ///停止扫描设备
  stopScanList() {
    _channelBlue.invokeMethod("stopScanList");
    if (_scanResultStreamController != null) {
      _scanResultStreamController.close();
    }
  }

  ///销毁蓝牙
  destroyBlue() async {
    _scanResultList!.clear();
    var str = await _channelBlue.invokeMethod("destory", {"id": devInfo!.id});
    print("destroyBlue ${str}");
  }

  ///断开设备
  disConnectBlue() async {
    var str =
        await _channelBlue.invokeMethod("disConnect", {"id": devInfo!.id});
    print("disConnectBlue ${str}");
  }

  /// 连接设备
  connect(ScanResults devInfo, List<String> uuidList, String serviceId,
      Function(bool isOk, String error) callback,
      {connectTimeout = 1000 * 10}) {
    this.devInfo = devInfo;
    _connectedCallBack = callback;
    _channelBlue.invokeMethod("connect", {
      "id": devInfo.id,
      "timeout": Platform.isAndroid ? connectTimeout : connectTimeout ~/ 1000,
      "isFromScan": false,
      "uuidList": uuidList,
      "serviceid": serviceId,
      "rssi": 0
    });
  }

  ///获取特征值
  getCharacteristicBeanList(
      Function(List<CharacteristicBean> list) listCallBack) {
    _characteristicBeanCallBack = listCallBack;
  }

  ///获取所有特征值
  getCharacteristicBeanAllList(
      Function(Map<dynamic, dynamic> map) listCallBack) {
    _characteristicBeanMapCallBack = listCallBack;
  }

  /// 根据特征值 获取测量数据
  ///使用设备的read特征值去向设备读取数据
  readDataByUUID(
      String serviceUuid,
      List<CharacteristicBean> characteristicList,
      Function(bool isSuccess, dynamic data, dynamic strdata, String uuid)
          callback) {
    CharacteristicBean bean;
    this.characteristicList = characteristicList;
    _valueMapCallBack = callback;
    // Map<String, CharacteristicBean> mapData = Map();
    // for (int i = 0; i < characteristicList.length; i++) {
    //   Future.delayed(const Duration(milliseconds: 1000*30), () {
    //     bean = characteristicList[i];
    //     //已连接才能去向设备写入数据
    //     print("发起取值${serviceUuid}--${bean.uuid}");
    //     _channelBlue.invokeMethod("readData", {
    //       "id": devInfo!.id,
    //       "serviceUuid": serviceUuid,
    //       "characteristicUuid": bean.uuid
    //     }); //去向设备读取数据
    //   });
    // }
  }

  /// 根据特征值 获取测量数据
  ///使用设备的read特征值去向设备读取数据
  readData(
      Function(bool isSuccess, dynamic data, dynamic strdata, String uuid)
          callback) {
    _valueMapCallBack = callback;
  }

  ///蓝牙的sdk跳转到某个activity
  sdkDevInit(String type) async {
    var str = await _channelBlue.invokeMethod("sdkDevInit", {"type": type});
    print("sdkDevInit ${str}");
  }

  sdkDevConnectBtn(String type,Function(String devType, String json) callJsonBack,Function(String devTye,String state, String msg) callStateBack) async {
    _valueSDKJsonCallBack = callJsonBack;
    _valueSDKStateCallBack = callStateBack;
    var str = await _channelBlue.invokeMethod("sdkDevConnectBtn", {"type": type});
    print("sdkDevConnectBtn ${str}");
  }

  sdkDestroyBlue(String type) async {
    var str = await _channelBlue.invokeMethod("sdkDestroyBlue", {"type": type});
    print("sdkDestroyBlue ${str}");
  }
}
